#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <unordered_map>
#include <queue>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory>


#include "thread.hpp"


// sock 唯一 ? 

uint16_t serverport = 0 ;
std::string serverip    ;

static void usage(std::string proc)
{
    std::cout<<  "\nUsage" << proc << "serverIp serverPort \n" << std::endl ; 
}

static void* udpSend(void* args)
{
    // int sock = ;
    int sock = *(int*)((ThreadData*)args)->_args ;
    std::string  name =((ThreadData*)args)->_name;

    std::string message;
    sockaddr_in server ;
    memset(&server, 0, sizeof(serverport));
    server.sin_family = AF_INET6 ;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str()) ; 

    while(true)
    {
        std::cerr << "请输入信息 #"  ;
        std::getline(std::cin, message);
        if(message == "quit")
        {
            break;
        }
        //sento函数中，该server参数指向目标地址的结构体指针，其中包含目标主机的IP地址和端口号
        sendto(sock, message.c_str(), message.size(), 0, (sockaddr*)&server, sizeof server );
    }

    return nullptr ; 
}


static void* udpRecv(void* args)
{
    int sock = * (int*) ((ThreadData*)args)->_args ;
    std::string name = ((ThreadData*)args)->_name  ;\

    char buffer[1024];
    while (true)
    {
        memset(buffer, 0, sizeof(buffer));
        sockaddr_in temp ;
        socklen_t len = sizeof temp ;
        //ssize_t是有符号整型
        //第一个参数用于指定要接收数据的套接字
        //buffer是接收缓冲区
        //temp 用于存储发送方地址的struct sockaddr结构体的指针
        ssize_t s = recvfrom (sock, buffer, sizeof buffer, 0, (sockaddr*)&temp, &len) ;
        if(s > 0)
        {
            buffer[s] = 0 ;
            std::cout << buffer << std::endl;
        }
    }
     
}

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }

    //套接字
    //AF_INET: 套接字协议域 ipv4
    //SOCK_DGRAM 套接字类型udp
    //0 ：自动选择套接字协议
    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    if(sock < 0)
    {
        std::cerr << "socket error " << std::endl ; 
        exit(2);
    }

    serverip = argv[1];
    serverport = atoi(argv [2]);

    // client要不要bind？？要，但是一般client不会显示的bind，程序员不会自己bind
    // client是一个客户端 -> 普通人下载安装启动使用的-> 如果程序员自己bind了->
    // client 一定bind了一个固定的ip和port，万一，其他的客户端提前占用了这个port呢？？
    // client一般不需要显示的bind指定port，而是让OS自动随机选择(什么时候做的呢？)

    std::unique_ptr<Thread> sender(new Thread(1, udpSend, (void*)&sock)) ;
    std::unique_ptr<Thread> recver(new Thread(2, udpRecv, (void*)&sock)) ;

    sender->start();
    recver->start();

    sender->join();
    recver->join();

    close(sock);

    return 0 ; 
}
